#include "oarray.h"

void mx_oarray_init (mx_oarray_pt poarray, mx_oarray_sort_t sort)
{
    assert_true(poarray != mx_null);
    
    poarray->count = 0;
    poarray->sort = sort;
    mx_dlist_init((mx_dlist_pt)poarray);
}

void mx_oarray_node_init (mx_oarray_node_pt pnode, mx_usize_t seque)
{
    assert_true(pnode != mx_null);

    pnode->owner = mx_null;
    pnode->seque = seque;
    mx_dlist_init((mx_dlist_pt)pnode);
}

void mx_oarray_remove (mx_oarray_node_pt pnode)
{
    assert_true(pnode != mx_null);

    if (pnode->owner != mx_null)
    {
        pnode->owner->count --;
        pnode->owner = mx_null;
        mx_dlist_remove((mx_dlist_pt)pnode);
    }
}

void mx_oarray_add (mx_oarray_pt poarray, mx_oarray_node_pt pnode)
{
    assert_true(poarray != mx_null);
    assert_true(pnode != mx_null);

    /* delete from source order array */
    if (pnode->owner != mx_null)
    {
        pnode->owner->count --;
        mx_dlist_remove((mx_dlist_pt)pnode);
    }

    poarray->count ++;
    pnode->owner = poarray;

    switch (poarray->sort)
    {
    case MX_OARRAY_SORT_ASCE:
        mx_oarray_foreach(poarray, n, {
            if (pnode->seque < n->seque)
            {
                mx_dlist_insert_before((mx_dlist_pt)n, (mx_dlist_pt)pnode);
                break;
            }
        });
        /* check whether the node has been inserted */
        if (((mx_dlist_pt)pnode)->next == (mx_dlist_pt)pnode)
        {
            mx_dlist_insert_before((mx_dlist_pt)poarray, (mx_dlist_pt)pnode);
        }
        break;
    case MX_OARRAY_SORT_DESC:
        mx_oarray_foreach_prev(poarray, n, {
            if (pnode->seque <= n->seque)
            {
                mx_dlist_insert_after((mx_dlist_pt)n, (mx_dlist_pt)pnode);
                break;
            }
        });
        /* check whether the node has been inserted */
        if (((mx_dlist_pt)pnode)->next == (mx_dlist_pt)pnode)
        {
            mx_dlist_insert_after((mx_dlist_pt)poarray, (mx_dlist_pt)pnode);
        }
        break;
    case MX_OARRAY_SORT_NONE:
        mx_dlist_insert_before((mx_dlist_pt)poarray, (mx_dlist_pt)pnode);
        break;
    default:
        assert_true(mx_false);
        break;
    }
}

mx_oarray_node_pt mx_oarray_get (mx_oarray_pt poarray, mx_usize_t index)
{
    mx_oarray_node_pt ret = mx_null;
    if (index < poarray->count)
    {
        mx_usize_t i;
        if (poarray->count - index - 1 < index)
        {
            i = poarray->count - 1;
            mx_oarray_foreach_prev(poarray, node, {
                if (i == index)
                {
                    ret = node;
                    break;
                }
                i --;
            });
        }
        else
        {
            i = 0;
            mx_oarray_foreach(poarray, node, {
                if (i == index)
                {
                    ret = node;
                    break;
                }
                i ++;
            });
        }
    }
    return ret;
}

mx_size_t mx_oarray_index (mx_oarray_node_pt pnode)
{
    mx_size_t count = -1;
    if (pnode->owner != mx_null)
    {
        mx_oarray_foreach(pnode->owner, node, {
            count ++;
            if (node == pnode)
            {
                break;
            }
        });
    }
    return count;
}

mx_size_t mx_oarray_count (mx_oarray_pt parray)
{
    return parray->count;
}

mx_bool_t mx_oarray_iscontain (mx_oarray_pt parray, mx_oarray_node_pt pnode)
{
    return (parray == pnode->owner);
}
